import os
import yaml
import signal
import sys
from flask import Flask, send_from_directory, redirect
from flask_cors import CORS
from pathlib import Path
from typing import Dict, List, Type
from utils.logger import Logger
from utils.config import Config
from modules.base import BaseModule

class Server:
    def __init__(self):
        # Initialize base directory
        self.base_dir = Path(__file__).resolve().parent

        print(f"base_dir: {self.base_dir}")
        
        # Load server configuration
        self.config = Config(base_dir=self.base_dir)
        self.server_config = self.load_server_config()
        
        # Initialize logger with configuration
        log_config = self.server_config.get('logging', {})

        self.logger = Logger(
            'chat',
            Path('./log/'),
            level=log_config.get('log_level', 'INFO'),
            max_size=log_config.get('max_size', 10*1024*1024),
            backup_count=log_config.get('backup_count', 5),
            filename_format=log_config.get('filename_format', 'chat_%Y%m%d.log')
        )

        # Initialize Flask application
        self.app = Flask(__name__)
        CORS(self.app)
        
        # Set React build folder as static folder
        self.app.static_folder = str(self.base_dir.parent / 'dist')
        print(f"web folder: {self.app.static_folder}")
        
        # Initialize modules
        self.modules: Dict[str, BaseModule] = {}
        self.load_modules()
        setup_html_routes(self.app)
        self.logger.info("Server initialized successfully")
        
    def load_server_config(self) -> dict:
        """Load server configuration from YAML file"""
        try:
            return self.config.load_config('server_config.yaml')
        except FileNotFoundError:
            self.logger.warning("Server config not found, using defaults")
            return {}
        except Exception as e:
            self.logger.error(f"Failed to load server config: {e}")
            return {}
            
    def load_modules(self):
        """Load and initialize all modules by dynamically scanning the modules directory"""
        try:
             # Find all module directories in modules
            modules_dir = self.base_dir / 'modules'
            # Skip these directories and files when scanning
            skip_items = {'__pycache__', '__init__.py', 'base.py', 'base'}
            
            self.logger.info(f"Scanning for modules in: {modules_dir}")
            
            # Scan directory for modules
            for item in modules_dir.iterdir():
                if item.is_dir() and item.name not in skip_items:
                    module_name = item.name
                    try:
                        # Import the module
                        module = __import__(f"modules.{module_name}", fromlist=['*'])
                        
                        # Find module class from __all__ declaration
                        if hasattr(module, '__all__') and module.__all__:
                            for cls_name in module.__all__:
                                if hasattr(module, cls_name):
                                    module_class = getattr(module, cls_name)
                                    if isinstance(module_class, type) and issubclass(module_class, BaseModule):
                                        # Initialize the module with configuration
                                        module_config = self.config.get(module_name, {})
                                        self.modules[module_name] = module_class(
                                            app=self.app,
                                            logger=self.logger,
                                            config=module_config
                                        )
                                        self.logger.info(f"Successfully loaded module: {module_name}")
                                        break
                            else:
                                self.logger.warning(f"No valid module class found in {module_name}.__all__")
                        else:
                            self.logger.warning(f"Module {module_name} has no __all__ declaration")
                            
                    except Exception as e:
                        self.logger.error(f"Failed to load module {module_name}: {e}")
                        
        except Exception as e:
            self.logger.error(f"Failed to load modules: {e}")
            
    def cleanup(self):
        """Cleanup all modules"""
        for module_name, module in self.modules.items():
            try:
                module.cleanup()
                self.logger.info(f"Successfully cleaned up module: {module_name}")
            except Exception as e:
                self.logger.error(f"Failed to cleanup module {module_name}: {e}")
                
    def run(self, host: str = '0.0.0.0', port: int = 5000):
        """Run the web server
        
        Args:
            host: Optional host address to override config
            port: Optional port number to override config
        """
        try:
            # Get host and port from config if not provided
            base_config = self.server_config.get('base', {})
            host = host or base_config.get('host', '0.0.0.0')
            port = port or base_config.get('port', 5000)
            debug = base_config.get('debug', True)
            
            self.logger.info(f"Starting web server on {host}:{port}")
            self.app.run(
                host=host,
                port=port,
                debug=debug,
                threaded=True
            )
        except Exception as e:
            self.logger.error(f"Failed to start web server: {e}")
        finally: 
            self.cleanup()



def setup_html_routes(app: Flask):
    # Updated routing for React SPA
    
    @app.route('/', defaults={'path': ''}) # type: ignore
    @app.route('/<path:path>')  # type: ignore
    def serve_react(path):
        # Check if the path is for API endpoints
        if path.startswith('api/'):
            # Let the API handlers process this request
            return app.view_functions[path]()
        static_folder = app.static_folder # type: ignore
        if not static_folder:
            static_folder = Path('./')
        
        # Check if the requested file exists in the static folder
        static_file_path = os.path.join(static_folder, path)
        if os.path.isfile(static_file_path):
            return send_from_directory(static_folder, path)
        
        # For all other routes, serve the React index.html
        # This enables client-side routing in the React app
        return send_from_directory(static_folder, 'index.html')

def signal_handler(signum, frame):
    """Signal handler for graceful shutdown"""
    print('Signal handler called with signal', signum)
    if 'server' in globals():
        server.cleanup()
    sys.exit(0)

def main():
    try:
        # Register signal handlers
        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)
        
        global server
        server = Server()
        server.run()
    except Exception as e:
        print(f"Server failed: {e}")
    finally:
        if 'server' in globals():
            server.cleanup()

if __name__ == '__main__':
    main()